<template>
	<view class="tabbar flex_y fs28 fw500 pr">
		<slot>
			<view class="tabbar__item" v-for="(item,index) in list" :class=" ['flex1 fjc',{active:checkIndex===index}]"
				:data-index="index" :data-item="item" @click="changTab">
				{{item.name}}
			</view>
		</slot>
		<view class="checK-active" :style="lineStyle"></view>
	</view>
</template>

<script>
	export default {
		props: {
			list: Array
		},
		data() {
			return {
				checkIndex: 0,
				lineStyle: '',
				lineWidth: 16
			}
		},
		watch: {
			checkIndex() {
				this.setLineLeft()
			}
		},
		mounted() {
			this.$nextTick(() => {
				this.getSize()
			})
		},
		methods: {
			changTab(e) {
				let {
					index,
					item
				} = e.target.dataset;
				this.checkIndex = index;
				this.$emit('click', {
					...item,
					index
				})
			},
			getSize() {
				// 获取所有标签的尺寸
				// 如果不存在list，则不处理
				if (this.list.length === 0) {
					return
				}
				Promise.all([this.getTabsRect(), this.getAllItemRect()]).then(([tabsRect, itemRect = []]) => {
					this.tabsRect = tabsRect
					this.scrollViewWidth = 0
					itemRect.map((item, index) => {
						// 计算scroll-view的宽度，这里
						this.scrollViewWidth += item.width
						// 另外计算每一个item的中心点X轴坐标
						this.list[index].rect = item
					})
					// 获取了tabs的尺寸之后，设置滑块的位置
					this.setLineLeft()
					this.setScrollLeft()
				})
			},
			setLineLeft() {
				const tabItem = this.list[this.checkIndex];
				if (!tabItem) {
					return;
				}
				// 获取滑块该移动的位置
				let lineOffsetLeft = this.list
					.slice(0, this.checkIndex)
					.reduce((total, curr) => total + curr.rect.width, 0);
				// 获取下划线的数值px表示法
				const lineWidth = this.lineWidth;
				this.lineOffsetLeft = lineOffsetLeft + (tabItem.rect.width - lineWidth) / 2
				this.lineStyle = `transform: translateX(${this.lineOffsetLeft}px);transition-duration:0.3s;`
				// 如果是第一次执行此方法，让滑块在初始化时，瞬间滑动到第一个tab item的中间
				// 这里需要一个定时器，因为在非nvue下，是直接通过style绑定过渡时间，需要等其过渡完成后，再设置为false(非第一次移动滑块)
				if (this.firstTime) {
					setTimeout(() => {
						this.firstTime = false
					}, 10);
				}
			},
			setScrollLeft() { //超出屏幕是否需要向左滑动
				// 当前活动tab的布局信息，有tab菜单的width和left(为元素左边界到父元素左边界的距离)等信息
				const tabRect = this.list[this.checkIndex]
				// 累加得到当前item到左边的距离
				const offsetLeft = this.list
					.slice(0, this.checkIndex)
					.reduce((total, curr) => {
						return total + curr.rect.width
					}, 0)
				// 此处为屏幕宽度
				const windowWidth = uni.$u.sys().windowWidth
				// 将活动的tabs-item移动到屏幕正中间，实际上是对scroll-view的移动
				let scrollLeft = offsetLeft - (this.tabsRect.width - tabRect.rect.width) / 2 - (windowWidth - this.tabsRect
					.right) / 2 + this.tabsRect.left / 2
				// 这里做一个限制，限制scrollLeft的最大值为整个scroll-view宽度减去tabs组件的宽度
				scrollLeft = Math.min(scrollLeft, this.scrollViewWidth - this.tabsRect.width)
				this.scrollLeft = Math.max(0, scrollLeft)
			},
			// 获取导航菜单的尺寸
			getTabsRect() {
				return new Promise(resolve => {
					this.queryRect('tabbar').then(size => {
						return resolve(size)
					})
				})
			},
			// 获取各个标签的尺寸
			queryRect(el, item) {
				return new Promise(resolve => {
					uni.$z.getRectInfo(`.${el}`, item, this).then(size => {
						resolve(size)
					})
				})
			},
			// 获取所有标签的尺寸
			getAllItemRect() {
				return new Promise(resolve => {
					let promiseAllArr = this.queryRect('tabbar__item', true).then(sizes => resolve(sizes))
				})
			},
		}
	}
</script>

<style lang="scss">
	.tabbar {
		// margin-top: -80rpx;
		height: 108rpx;
		color: #A7A7A7;
		background: #FFFFFF;

		>view {
			height: inherit;
		}

		.active {
			font-weight: 500;
			color: #333;
		}

		.checK-active {
			content: '';
			position: absolute;
			bottom: 16rpx;
			width: 32rpx;
			height: 8rpx;
			border-radius: 4rpx;
			background: #FF7803;
		}
	}
</style>